package com.gcloud.mesh.supplier.adapter;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.gcloud.mesh.dcs.enums.AliPowerEventRepType;
import com.gcloud.mesh.header.msg.supplier.AliPowerBaseMsg;
import com.gcloud.mesh.header.msg.supplier.AliPowerListDevicePageReqMsg;
import com.gcloud.mesh.header.vo.supplier.AliPower.*;
import com.gcloud.mesh.header.vo.supplier.AliPowerConsumptionVo;
import com.gcloud.mesh.supplier.dao.SupplierDao;
import com.gcloud.mesh.supplier.entity.SupplierEntity;
import com.gcloud.mesh.utils.SupplierSystemTypeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class AliPowerConsumptionAdapter extends AbstractAdapter {

    private static final String HTTP = "http://";

    private static final String TYPE = "ali_powerconsumption";

    @Autowired
    private SupplierDao supplierDao;

    /**
     * Key:datacenter_id
     * Value:AliPowerConsumptionVo
     **/
    private Map<String, AliPowerConsumptionVo> aliPowerMap = new HashMap<>();

    /**
     * Key:device_id
     * Value:datacenter_id
     **/
    private Map<String, String> devicesMap = new HashMap<>();

    @PostConstruct
    private void init() {
        List<SupplierEntity> suppliers = supplierDao.findAll().stream().filter(s -> TYPE.equals(s.getType())).collect(Collectors.toList());
        for (SupplierEntity supplier : suppliers) {
            AliPowerConsumptionVo vo = (AliPowerConsumptionVo) SupplierSystemTypeUtil.getByName(supplier.getType(), supplier.getConfig());
            if (vo != null && !StringUtils.isEmpty(supplier.getDatacenterId())) {
                aliPowerMap.put(supplier.getDatacenterId(), vo);
            } else {
                log.info("[AliPowerConsumptionAdapter]数据中心id:{}的配置转换出错或者数据中心id为空", supplier.getDatacenterId());
            }
        }
        log.info("[AliPowerConsumptionAdapter]功耗平台的数据中心分别有{}，链接为:{}", aliPowerMap.keySet(), aliPowerMap.values().stream().map(AliPowerConsumptionVo::getHostIp).toArray());
    }


    @Override
    public String getToken() {
        return null;
    }


    /**
     * 设备列表
     */
    public List<AliPowerDeviceVo> listDevices(AliPowerListDevicePageReqMsg msg) {
        if (aliPowerMap == null || aliPowerMap.isEmpty()) {
            return Collections.emptyList();
        }
        List<AliPowerDeviceVo> result = new ArrayList<>();
        //遍历所有的数据中心下的功耗平台
        for (Map.Entry<String, AliPowerConsumptionVo> alipower : aliPowerMap.entrySet()) {
            String urlPath = "/v2/powermarket/bid/devices";
            String uri = String.format("%s%s%s", HTTP, alipower.getValue().getHostIp(), urlPath);
            String tokenStr = "idToken=" + alipower.getValue().getIdToken();
            StringBuilder s = new StringBuilder();
            if (!StringUtils.isEmpty(msg.getBusiness_type())) {
                s.append("&business_type=").append(msg.getBusiness_type());
            }
            if (!StringUtils.isEmpty(msg.getCondition())) {
                s.append("&condition=").append(msg.getCondition());
            }
            if (!StringUtils.isEmpty(msg.getType())) {
                s.append("&type=").append(msg.getType());
            }
            if (!StringUtils.isEmpty(msg.getUsage_status())) {
                s.append("&usage_status=").append(msg.getUsage_status());
            }
            if (msg.getPageNum() >= 1) {
                s.append("&pageNum=").append(msg.getPageNum());
            }
            if (msg.getPageSize() != 0) {
                s.append("&pageSize=").append(msg.getPageSize());
            }
            if (!StringUtils.isEmpty(msg.getCabinet_sn())) {
                s.append("&cabinet_sn=").append(msg.getCabinet_sn());
            }
            String paramsStr = s.toString();
            paramsStr = tokenStr + paramsStr;
            HttpHeaders headers = new HttpHeaders();
            log.info("[AliPowerConsumptionAdapter]获取设备列表url:{},param:{}", uri, paramsStr);
            String res = this.get(uri, headers, paramsStr);
            if (res != null) {
                AliPowerBaseMsg<List<AliPowerDeviceVo>> devicePageMsg =
                        JSONArray.parseObject(res, new TypeReference<AliPowerBaseMsg<List<AliPowerDeviceVo>>>() {
                        });
                if (Objects.equals(devicePageMsg.getErr_code(), "0")
                        && devicePageMsg.getData() != null
                        && devicePageMsg.getData().containsKey("devices")) {
                    List<AliPowerDeviceVo> devices = devicePageMsg.getData().get("devices");

                    for (AliPowerDeviceVo device : devices) {
                        device.setAddress(alipower.getKey());
                        result.add(device);
                        //重新整理devicesMap
                        if (devicesMap.containsKey(device.getId())) {
                            devicesMap.replace(device.getId(), alipower.getKey());
                        } else {
                            devicesMap.put(device.getId(), alipower.getKey());
                        }

                    }
                    ;
                }
            }
        }
        return result;
    }

    /**
     * 获取所有设备
     */
    public List<AliPowerDeviceVo> getAllDevices() {
        AliPowerListDevicePageReqMsg msg = new AliPowerListDevicePageReqMsg();
        msg.setPageNum(1)
                .setPageSize(-1);
        return this.listDevices(msg);
    }

    /**
     * 服务器详情信息
     */
    public AliPowerDeviceMapVo detailNode(String deviceId) {
        if (aliPowerMap == null || aliPowerMap.isEmpty() || devicesMap.isEmpty()) {
            return null;
        }
        String datacenterId = devicesMap.get(deviceId);
        String url = "/v2/powermaster/devices/" + deviceId;
        String uri = String.format("%s%s%s", HTTP, aliPowerMap.get(datacenterId).getHostIp(), url);
        String tokenStr = "idToken=" + aliPowerMap.get(datacenterId).getIdToken();
        log.info("[AliPowerConsumptionAdapter]获取服务器详情设备id:{}，数据中心id:{}", deviceId, datacenterId);
        log.info("[AliPowerConsumptionAdapter]获取服务器详情url:{}", uri);
        String res = this.get(uri, new HttpHeaders(), tokenStr);
        if (res != null) {
            AliPowerBaseMsg<AliPowerDeviceMapVo> msg =
                    JSONObject.parseObject(res, new TypeReference<AliPowerBaseMsg<AliPowerDeviceMapVo>>() {
                    });
            if (Objects.equals(msg.getErr_code(), "0")
                    && msg.getData() != null
                    && msg.getData().containsKey("map")) {
                return msg.getData().get("map");
            }
        }
        return null;

    }


    /**
     * 申请、释放资源，当price>=0，当price=0时释放资源
     */
    public void bid(String deviceId, int price) {
        if (aliPowerMap == null || aliPowerMap.isEmpty() || devicesMap.isEmpty()) {
            return;
        }
        String datacenterId = devicesMap.get(deviceId);
        String url = "/v2/powermarket/bid/bid";
        String uri = String.format("%s%s%s", HTTP, aliPowerMap.get(datacenterId).getHostIp(), url);
        AliPowerBidParamVo paramVo = new AliPowerBidParamVo();
        paramVo.setDevice_id(deviceId);
        paramVo.setPrice(price);
        paramVo.setIdToken(aliPowerMap.get(datacenterId).getIdToken());
        String paramStr = JSONObject.toJSONString(paramVo);
        log.info("[AliPowerConsumptionAdapter]申请、释放资源url:{},param:{}", uri, paramVo);
        this.post(uri, new HttpHeaders(), paramStr);
    }

    /**
     * 申请资源
     *
     * @param deviceId 设备esn
     */
    public void applyDevice(String deviceId) {
        int applyPrice = 100;
        this.bid(deviceId, applyPrice);
    }


    /**
     * 释放资源
     *
     * @param deviceId 设备esn
     */
    public void releaseDevice(String deviceId) {
        int releasePrice = 0;
        this.bid(deviceId, releasePrice);
    }

    /**
     * 关注调度事件
     */

    public List<AliPowerEventRepVo> events() {
        if (aliPowerMap == null || aliPowerMap.isEmpty()) {
            return Collections.emptyList();
        }
        List<AliPowerEventRepVo> result = new ArrayList<>();
        for (Map.Entry<String, AliPowerConsumptionVo> alipower : aliPowerMap.entrySet()) {
            String url = "/v2/powermarket/bid/events";
            String uri = String.format("%s%s%s", HTTP, alipower.getValue().getHostIp(), url);
            String tokenStr = "idToken=" + alipower.getValue().getIdToken();
            SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
            factory.setReadTimeout(60 * 1000);
            factory.setConnectTimeout(60 * 1000);
            log.info("[AliPowerConsumptionAdapter]关注调度事件url:{}", uri);
            String res = this.get(uri, new HttpHeaders(), tokenStr, factory);
            if (res != null) {
                AliPowerBaseMsg<AliPowerEventRepVo> msg =
                        JSONObject.parseObject(res, new TypeReference<AliPowerBaseMsg<AliPowerEventRepVo>>() {
                        });
                if (Objects.equals(msg.getErr_code(), "0")
                        && msg.getData() != null
                        && msg.getData().containsKey("event")) {
                    AliPowerEventRepVo eventRepVo = msg.getData().get("event");
                    if (AliPowerEventRepType.getByName(eventRepVo.getType()) != null
                            && !StringUtils.isEmpty(eventRepVo.getValue())) {
                        result.add(eventRepVo);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 获取设备动态信息，包括功耗
     */
    public AliPowerDeviceDenamicVo deviceDenamic(String deviceId) {
        if (aliPowerMap == null || aliPowerMap.isEmpty() || devicesMap.isEmpty()) {
            return null;
        }
        String datacenterId = devicesMap.get(deviceId);
        String url = "/v2/powermaster/devices/denamic/";
        String uri = String.format("%s%s%s%s", HTTP, aliPowerMap.get(datacenterId).getHostIp(), url, deviceId);
        String tokenStr = "idToken=" + aliPowerMap.get(datacenterId).getIdToken();
        log.info("[AliPowerConsumptionAdapter]获取设备动态信息url:{}", uri);
        String res = this.get(uri, new HttpHeaders(), tokenStr);
        if (res != null) {
            AliPowerBaseMsg<AliPowerDeviceDenamicVo> msg =
                    JSONObject.parseObject(res, new TypeReference<AliPowerBaseMsg<AliPowerDeviceDenamicVo>>() {
                    });
            if (Objects.equals(msg.getErr_code(), "0")
                    && msg.getData() != null
                    && msg.getData().containsKey("map")) {
                return msg.getData().get("map");
            }
        }
        return null;
    }

    /**
     * 设备信息，通用，包括服务器、机柜、空调、PDU这些
     *
     * @param deviceId     esn
     * @param datacenterId 设备所在的数据中心id
     */
    public Map<String, String> detailDevice(String deviceId, String datacenterId) {
        if (aliPowerMap == null || aliPowerMap.isEmpty() || devicesMap.isEmpty()) {
            return null;
        }
        String url = "/v2/powermaster/devices/" + deviceId;
        String uri = String.format("%s%s%s", HTTP, aliPowerMap.get(datacenterId).getHostIp(), url);
        String tokenStr = "idToken=" + aliPowerMap.get(datacenterId).getIdToken();
        log.info("[AliPowerConsumptionAdapter]获取设备详情设备id:{}，数据中心id:{}", deviceId, datacenterId);
        log.info("[AliPowerConsumptionAdapter]获取设备详情url:{}", uri);
        String res = this.get(uri, new HttpHeaders(), tokenStr);
        if (res != null) {
            JSONObject jsonMsg = JSONObject.parseObject(res);
            if (jsonMsg.containsKey("err_code")
                    && Objects.equals(jsonMsg.getString("err_code"), "0")
                    && jsonMsg.containsKey("data")) {
                JSONObject jsonData = jsonMsg.getJSONObject("data");
                return jsonData.containsKey("map") ? JSONObject.parseObject(jsonData.getString("map"), new TypeReference<Map<String, String>>() {
                }) : null;
            }
        }
        return null;

    }


}
